#!/usr/bin/python3
# ******************************************************************************
# Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
# licensed under the Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#     http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
# PURPOSE.
# See the Mulan PSL v2 for more details.
# Author: Jiachen Fan
# Create: 2021-3-19
# ******************************************************************************/
import argparse
import requests
import os
import abc
import logging
import yaml
import subprocess
import pandas as pd

from src.util.requests_util import requests_get_content
from src.util.spec import Spec, replace_macros
from src.util.osc_utils import get_osc_pkg_nvr
from src.util.dnf_utils import dnf_list_src_version

VERSION_CONF_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 "config",
                                 "openEuler_branch.yaml")

"""
dnf install rpmdevtools
"""


class PkgVerInterface(metaclass=abc.ABCMeta):
    """
    interface for get version from repo(i.e. gitee/obs/repo.openeuler.org)
    """

    def __init__(self, name, branch):
        self.name = name
        self.version = ""
        self.release = ""
        self.epoch = "0"
        self.branch = branch

    def get_vr(self):
        if not self.version or not self.release:
            return "unknow"
        return "{ver}-{rel}" \
            .format(
            ver=self.version,
            rel=self.release
        )

    def get_evr(self):
        if not self.version or not self.release:
            return "unknow"
        return "{epoch}{ver}-{rel}" \
            .format(
            epoch="" if self.epoch == "0" else (self.epoch + ":"),
            ver=self.version,
            rel=self.release
        )

    def __str__(self):
        return self.get_evr()

    @abc.abstractmethod
    def parse_content(self):
        pass


class GiteePkgVer(PkgVerInterface):
    """
    get pkg version from src-openeuler/pkg -> pkg.spec in xxx branch
    parse spec to get Version:str, Release:str, Epoch:str(default 0) 
    """

    def __init__(self, name, branch):
        super(GiteePkgVer, self).__init__(name, branch)
        self.spec_format_url = "https://gitee.com/src-openeuler/{name}/raw/{branch}/{name}.spec".format(
            name=self.name,
            branch=self.branch
        )

    def _check_branch(self):
        openEuler_branch = {}
        if not os.path.isfile(VERSION_CONF_FILE):
            print("openEuler branch config file:[%s] not exist", openEuler_branch)
            return False
        with open(VERSION_CONF_FILE, "r") as f:
            openEuler_branch = yaml.safe_load(f)
        if not openEuler_branch or not openEuler_branch["openEuler_branch"].get(self.branch, None):
            print("[%s] is not a openEuler branch name", self.branch)
            return False
        return True

    def _rpmspec_parse(self, file_name):
        if not os.path.isfile(file_name):
            print("spec file %s not exist", os.path.basename(file_name))
            return

        cmd_list = ["rpmspec", "--parse", file_name]
        try:
            proc = subprocess.Popen(cmd_list, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        except OSError as e:
            print("oserror: %s", str(e))
            return None, None
        stdout, stderr = proc.communicate()
        returncode = proc.returncode
        proc.poll()
        if returncode == 0:
            inputspec = Spec.from_string(stdout.decode("utf-8", "ignore"))
        else:
            inputspec = Spec.from_file(file_name)
        self.version = replace_macros(inputspec.version, inputspec)
        self.release = replace_macros(inputspec.release, inputspec)

    def _parse_spec(self, content, savedir="/tmp/update-package", save=False):
        _ = not os.path.exists(savedir) and os.makedirs(savedir)
        file_name = os.path.join(savedir, "{}.spec".format(self.name))
        if os.path.isfile(file_name):
            os.remove(file_name)
        with open(file_name, "a") as f:
            f.write(content)
        self._rpmspec_parse(file_name)
        if not save and os.path.exists(file_name):
            os.remove(file_name)

    def parse_content(self):
        if not self.name or not self.branch:
            print("name or branch fields not exists")
            return
        #print(self.spec_format_url)
        if not self._check_branch():
            print("check branch failed")
            return
        status_code, content = requests_get_content(self.spec_format_url, timeout=30)
        #print(status_code)
        #print(content)
        if not content:
            return
        self._parse_spec(content)


class OBSPkgVer(PkgVerInterface):
    """
    get pkg version from repo 
    """
    REPO_ARCH_DICT = {
        "arm": {
            "repo": "standard_aarch64",
            "arch": "aarch64"
        },
        "x86": {
            "repo": "standard_x86_64",
            "arch": "x86_64"
        }
    }

    def __init__(self, name, branch):
        super(OBSPkgVer, self).__init__(name, branch)

    def _check_parse_branch(self):
        pass

    def _get_repo_arch(self, arch_key):
        if arch_key not in self.REPO_ARCH_DICT:
            print("[%s] key is not support", arch_key)
            return "", ""
        return self.REPO_ARCH_DICT[arch_key].get("repo", ""), \
               self.REPO_ARCH_DICT[arch_key].get("arch", "")

    def parse_content(self):
        self._check_parse_branch()
        arch_list = self.REPO_ARCH_DICT.keys()
        #print(arch_list)
        for key in arch_list:
            repo, arch = self._get_repo_arch(key)
            name, ver, rel = get_osc_pkg_nvr(self.name, self.branch, repo=repo, arch=arch)
            #print("obs info:",name,ver,rel)
            if ver:
                self.version, self.release = ver, rel
                break


class DNFPkgVer(PkgVerInterface):
    def __init__(self, name, repo_list):
        super(DNFPkgVer, self).__init__(name, repo_list)

    def parse_content(self):
        self.epoch, self.version, self.release = dnf_list_src_version(self.name, self.branch)


class RepoPkgVer(object):
    """
    to simply dip
    use this case to get repo version and 
    """

    def __init__(self, repo_pkg_ver):
        self.repo_pkg_ver = repo_pkg_ver

    def parse_ver_info(self):
        """
        use this function to fill version info into repo_pkg_ver
        use this after init this function
        """
        self.repo_pkg_ver.parse_content()

    def get_version(self):
        """
        get pkg [version] from self.repo_pkg_ver
        """
        return self.repo_pkg_ver.version

    def get_release(self):
        """
        get pkg [release] from self.repo_pkg_ver
        """
        return self.repo_pkg_ver.release

    def get_epoch(self):
        """
        get pkg [epoch] from self.repo_pkg_ver
        """
        return self.repo_pkg_ver.epoch

    def get_vr(self):
        """
        get pkg [version-release] from self.repo_pkg_ver
        """
        return self.repo_pkg_ver.get_vr()

    def get_evr(self):
        """
        get pkg [epoch:version-release] from self.repo_pkg_ver
        """
        return self.repo_pkg_ver.get_evr()

    def __str__(self):
        """
        usage same as get_evr
        print(RepoPkgVer) -> [epoch:version-release]
        """
        return self.repo_pkg_ver.get_evr()


def get_pkgs():
    pkg_list = []
    try:
        file = open("update_pkgs.txt")
        for line in file:
            if line.strip():
                pkg_list.append(line.strip())
    except FileNotFoundError:
        print("update_pkgs.txt can not found")
    except UnicodeDecodeError as err:
        print(err)
    return pkg_list


def get_pkgs_csv(repo_info_list):
        total_DF = pd.DataFrame(columns=['pkgs', 'gitee-SP1', 'obs-SP1', "sp1-res", "gitee-SP3", "obs-SP3", "sp3-res", "gitee-2203", "obs-2203", "2203-res"])
        for pkg_repo in repo_info_list:
            for pkg, repo_info in pkg_repo.items():
                data_dict = {'pkgs': pkg,
                             "gitee-SP1": repo_info[0],                                                               
                             "obs-SP1": repo_info[1],
                             "sp1-res": repo_info[2],
                             "gitee-SP3": repo_info[3],
                             "obs-SP3": repo_info[4],
                             "sp3-res": repo_info[5],
                             "gitee-2203": repo_info[6],
                             "obs-2203": repo_info[7],
                             "2203-res": repo_info[8]
                             }
                build_DF = pd.DataFrame(data=data_dict, index=[0])
                if len(build_DF):
                   total_DF = pd.concat([total_DF, build_DF], axis=0)
        total_DF.index = range(len(total_DF))
        total_DF.to_csv("update_pkgs_repo.csv")

def compare_pkg_ver(pkg_list,user_id,origin_repo=GiteePkgVer, new_repo=OBSPkgVer):
    # pkg_list = get_pkgs()
    gitee_branch_list = ["openEuler-20.03-LTS-SP1","openEuler-20.03-LTS-SP3", "openEuler-22.03-LTS"]
    obs_branch_list = ["openEuler:20.03:LTS:SP1", "openEuler:20.03:LTS:SP3", "openEuler:22.03:LTS"]

    repo_info_dict = []
    for pkg in pkg_list:

        pkg_version_list = []
        for branch_index in range(len(gitee_branch_list)):
            old_pkg_repo = RepoPkgVer(origin_repo(pkg, gitee_branch_list[branch_index]))
            new_pkg_repo = RepoPkgVer(new_repo(pkg, obs_branch_list[branch_index]))
            epol_pkg_repo = RepoPkgVer(
                new_repo(pkg, obs_branch_list[branch_index] + ":Epol")
            )
            old_pkg_repo.parse_ver_info()
            new_pkg_repo.parse_ver_info()
            epol_pkg_repo.parse_ver_info()

            pkg_version_list.append(old_pkg_repo.get_vr())
            if new_pkg_repo.get_vr() == "unknow":
                pkg_version_list.append(epol_pkg_repo.get_vr())
                if old_pkg_repo.get_vr() == epol_pkg_repo.get_vr():
                    pkg_version_list.append("same")
                else:
                    pkg_version_list.append("not same")
            else:
                pkg_version_list.append(new_pkg_repo.get_vr())
                if old_pkg_repo.get_vr() == new_pkg_repo.get_vr():
                    pkg_version_list.append("same")
                else:
                    pkg_version_list.append("not same")
        repo_info_dict.append({pkg: pkg_version_list})
    content = {"data": {"check_version": repo_info_dict, "id": user_id}}
    content.update(
        {"code": "200", "msg": "Succeeded check version"}
    ) if repo_info_dict else content.update(
        {"code": "400", "msg": "Failed to get check version"}
    )
    print(content)
    return repo_info_dict

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Cloud archive file upload")
    parser.add_argument(
        "--pkglist",
        required=True,
        nargs='+',
        help="package names")
    parser.add_argument(
        "--id",
        required=True,
        type=str,
        help="package name")
    args = parser.parse_args()
    res = compare_pkg_ver(args.pkglist, args.id)
    
